home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _utilities / utilities / 003 / _gs / !GS / c / GXPATH < prev    next >
Text File  |  1991-10-26  |  11KB  |  377 lines

  1. /* Copyright (C) 1989, 1990 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gxpath.c */
  21. /* Private path routines for GhostScript library */
  22. #include "gx.h"
  23. #include "gserrors.h"
  24. #include "gxfixed.h"
  25. #include "gzpath.h"
  26.  
  27. /* These routines all assume that all points are */
  28. /* already in device coordinates, and in fixed representation. */
  29. /* As usual, they return either 0 or a (negative) error code. */
  30.  
  31. /* Forward references */
  32. private subpath *path_alloc_copy(P1(gx_path *));
  33. private int gx_path_new_subpath(P1(gx_path *));
  34. #ifdef DEBUG
  35. void gx_print_segment(P1(segment *));
  36. #endif
  37.  
  38. /* ------ Initialize/free paths ------ */
  39.  
  40. /* Initialize a path */
  41. void
  42. gx_path_init(register gx_path *ppath, gs_memory_procs *pprocs)
  43. {    ppath->memory_procs = *pprocs;
  44.     ppath->box_last = 0;
  45.     ppath->position_valid = 0;
  46.     ppath->first_subpath = ppath->current_subpath = 0;
  47.     ppath->subpath_count = 0;
  48.     ppath->segment_count = 0;
  49.     ppath->curve_count = 0;
  50.     ppath->subpath_open = 0;
  51.     ppath->shares_segments = 0;
  52. }
  53.  
  54. /* Release the contents of a path.  We do this in reverse order */
  55. /* so as to maximize LIFO allocator behavior. */
  56. void
  57. gx_path_release(gx_path *ppath)
  58. {    segment *pseg;
  59.     if ( ppath->first_subpath == 0 ) return;    /* empty path */
  60.     if ( ppath->shares_segments ) return;    /* segments are shared */
  61.     pseg = (segment *)ppath->current_subpath->last;
  62.     while ( pseg )
  63.        {    segment *prev = pseg->prev;
  64.         static uint sizes[] = { segment_type_sizes };
  65. #ifdef DEBUG
  66. if ( gs_debug['p'] )
  67.         dprintf("[p]release"), gx_print_segment(pseg);
  68. #endif
  69.         (*ppath->memory_procs.free)((char *)pseg, 1, sizes[(int)pseg->type], "gx_path_release");
  70.         pseg = prev;
  71.        }
  72.     ppath->first_subpath = 0;    /* prevent re-release */
  73. }
  74.  
  75. /* Mark a path as shared */
  76. void
  77. gx_path_share(gx_path *ppath)
  78. {    if ( ppath->first_subpath ) ppath->shares_segments = 1;
  79. }
  80.  
  81. /* ------ Incremental path building ------ */
  82.  
  83. /* Macro for opening the current subpath. */
  84. /* ppath points to the path; psub has been set to ppath->current_subpath. */
  85. #define path_open()\
  86.     if ( !ppath->subpath_open )\
  87.        {    int code;\
  88.         if ( !ppath->position_valid )\
  89.           return_error(gs_error_nocurrentpoint);\
  90.         code = gx_path_new_subpath(ppath);\
  91.         if ( code < 0 ) return code;\
  92.         psub = ppath->current_subpath;\
  93.        }
  94.  
  95. /* Macros for allocating path segments. */
  96. /* Note that they assume that ppath points to the path, */
  97. /* and that psub points to the current subpath. */
  98. /* We have to split the macro into two because of limitations */
  99. /* on the size of a single statement (sigh). */
  100. #ifdef DEBUG
  101. #define p_alloc(pseg,size)\
  102.   if ( gs_debug['A'] ) dprintf2("[p]%lx<%u>\n", (ulong)pseg, size)
  103. #else
  104. #define p_alloc(pseg,size) 0
  105. #endif
  106. #define path_unshare(set_psub)\
  107.   if(ppath->shares_segments)\
  108.     if(!(set_psub path_alloc_copy(ppath)))return_error(gs_error_limitcheck)
  109. #define path_alloc_segment(pseg,ctype,stype,cname)\
  110.   path_unshare(psub=);\
  111.   if( !(pseg = (ctype *)(*ppath->memory_procs.alloc)(1, sizeof(ctype), cname)) )\
  112.     return_error(gs_error_limitcheck);\
  113.   p_alloc((char *)pseg, sizeof(ctype));\
  114.   pseg->type = stype, pseg->next = 0
  115. #define path_alloc_link(pseg)\
  116.   { segment *prev = psub->last;\
  117.     prev->next = (segment *)pseg;\
  118.     pseg->prev = prev;\
  119.     psub->last = (segment *)pseg;\
  120.   }
  121.  
  122. /* Open a new subpath */
  123. private int
  124. gx_path_new_subpath(gx_path *ppath)
  125. {    subpath *psub = ppath->current_subpath;
  126.     register subpath *spp;
  127.     path_alloc_segment(spp, subpath, s_start, "gx_path_new_subpath");
  128.     spp->last = (segment *)spp;
  129.     spp->line_count = spp->curve_count = 0;
  130.     spp->closed = 0;
  131.     spp->pt = ppath->position;
  132.     ppath->subpath_open = 1;
  133.     if ( !psub )            /* first subpath */
  134.        {    ppath->first_subpath = spp;
  135.         spp->prev = 0;
  136.        }
  137.     else
  138.        {    segment *prev = psub->last;
  139.         prev->next = (segment *)spp;
  140.         spp->prev = prev;
  141.        }
  142.     ppath->current_subpath = spp;
  143.     ppath->subpath_count++;
  144. #ifdef DEBUG
  145. if ( gs_debug['p'] )
  146.     dprintf("[p]"), gx_print_segment((segment *)spp);
  147. #endif
  148.     return 0;
  149. }
  150.  
  151. /* Add a point to the current path (moveto). */
  152. int
  153. gx_path_add_point(register gx_path *ppath, fixed x, fixed y)
  154. {    ppath->subpath_open = 0;
  155.     ppath->position_valid = 1;
  156.     ppath->position.x = x;
  157.     ppath->position.y = y;
  158.     return 0;
  159. }
  160.  
  161. /* Add a relative point to the current path (rmoveto). */
  162. int
  163. gx_path_add_relative_point(register gx_path *ppath, fixed dx, fixed dy)
  164. {    if ( !ppath->position_valid )
  165.       return_error(gs_error_nocurrentpoint);
  166.     ppath->subpath_open = 0;
  167.     ppath->position.x += dx;
  168.     ppath->position.y += dy;
  169.     return 0;
  170. }
  171.  
  172. /* Set the segment point and the current point in the path. */
  173. /* Assumes ppath points to the path. */
  174. #define path_set_point(pseg, fx, fy)\
  175.     (pseg)->pt.x = ppath->position.x = (fx),\
  176.     (pseg)->pt.y = ppath->position.y = (fy)
  177.  
  178. /* Add a line to the current path (lineto). */
  179. int
  180. gx_path_add_line(gx_path *ppath, fixed x, fixed y)
  181. {    subpath *psub = ppath->current_subpath;
  182.     register line_segment *lp;
  183.     path_open();
  184.     path_alloc_segment(lp, line_segment, s_line, "gx_path_add_line");
  185.     path_alloc_link(lp);
  186.     path_set_point(lp, x, y);
  187.     psub->line_count++;
  188.     ppath->segment_count++;
  189. #ifdef DEBUG
  190. if ( gs_debug['p'] )
  191.     dprintf("[p]"), gx_print_segment((segment *)lp);
  192. #endif
  193.     return 0;
  194. }
  195.  
  196. /* Add a rectangle to the current path. */
  197. /* This is a special case of adding a parallelogram. */
  198. int
  199. gx_path_add_rectangle(gx_path *ppath, fixed x0, fixed y0, fixed x1, fixed y1)
  200. {    return gx_path_add_pgram(ppath, x0, y0, x0, y1, x1, y1);
  201. }
  202.  
  203. /* Add a parallelogram to the current path. */
  204. /* This is equivalent to an add_point, three add_lines, */
  205. /* and a close_subpath. */
  206. int
  207. gx_path_add_pgram(gx_path *ppath,
  208.   fixed x0, fixed y0, fixed x1, fixed y1, fixed x2, fixed y2)
  209. {    int code;
  210.      if (    (code = gx_path_add_point(ppath, x0, y0)) < 0 ||
  211.         (code = gx_path_add_line(ppath, x1, y1)) < 0 ||
  212.         (code = gx_path_add_line(ppath, x2, y2)) < 0 ||
  213.         (code = gx_path_add_line(ppath, x0 + x2 - x1, y0 + y2 - y1)) < 0 ||
  214.         (code = gx_path_close_subpath(ppath)) < 0
  215.        ) return code;
  216.     return 0;
  217. }
  218.  
  219. /* Add a curve to the current path (curveto). */
  220. int
  221. gx_path_add_curve(gx_path *ppath,
  222.   fixed x1, fixed y1, fixed x2, fixed y2, fixed x3, fixed y3)
  223. {    subpath *psub = ppath->current_subpath;
  224.     register curve_segment *lp;
  225.     path_open();
  226.     path_alloc_segment(lp, curve_segment, s_curve, "gx_path_add_curve");
  227.     path_alloc_link(lp);
  228.     lp->p1.x = x1;
  229.     lp->p1.y = y1;
  230.     lp->p2.x = x2;
  231.     lp->p2.y = y2;
  232.     path_set_point(lp, x3, y3);
  233.     psub->curve_count++;
  234.     ppath->segment_count++;
  235.     ppath->curve_count++;
  236. #ifdef DEBUG
  237. if ( gs_debug['p'] )
  238.     dprintf("[p]"), gx_print_segment((segment *)lp);
  239. #endif
  240.     return 0;
  241. }
  242.  
  243. /* Add an approximation of an arc to the current path. */
  244. /* Parameters are the initial and final points of the arc, */
  245. /* and the point at which the extended tangents meet.*/
  246. /* We assume that the arc is less than a semicircle. */
  247. /* The arc may go either clockwise or counterclockwise. */
  248. /* The approximation is a very simple one: a single curve */
  249. /* whose other two control points are .55 of the way to the */
  250. /* intersection of the tangents.  This appears to produce a */
  251. /* very accurate circular arc: I haven't worked out the math */
  252. /* to understand why. */
  253. #define arc_magic 0.55
  254. int
  255. gx_path_add_arc(gx_path *ppath,
  256.   fixed x0, fixed y0, fixed x3, fixed y3, fixed xt, fixed yt)
  257. {    return gx_path_add_curve(ppath,
  258.             x0 + (fixed)((xt - x0) * arc_magic),
  259.             y0 + (fixed)((yt - y0) * arc_magic),
  260.             x3 + (fixed)((xt - x3) * arc_magic),
  261.             y3 + (fixed)((yt - y3) * arc_magic),
  262.             x3, y3);
  263. }
  264.  
  265. /* Close the current subpath. */
  266. int
  267. gx_path_close_subpath(gx_path *ppath)
  268. {    subpath *psub = ppath->current_subpath;
  269.     register line_close_segment *lp;
  270.     if ( !ppath->subpath_open ) return 0;
  271.     path_alloc_segment(lp, line_close_segment, s_line_close,
  272.                "gx_path_close_subpath");
  273.     path_alloc_link(lp);
  274.     path_set_point(lp, psub->pt.x, psub->pt.y);
  275.     lp->sub = psub;
  276.     psub->line_count++;
  277.     ppath->segment_count++;
  278.     psub->closed = 1;
  279.     ppath->subpath_open = 0;
  280. #ifdef DEBUG
  281. if ( gs_debug['p'] )
  282.     if ( lp != 0 )
  283.       dprintf("[p]"), gx_print_segment((segment *)lp);
  284. #endif
  285.     return 0;
  286. }
  287.  
  288. /* ------ Internal routines ------ */
  289.  
  290. /* Copy the current path, because it was shared. */
  291. /* Return a pointer to the current subpath, or 0. */
  292. private subpath *
  293. path_alloc_copy(gx_path *ppath)
  294. {    gx_path path_new;
  295.     int code;
  296.     code = gx_path_copy(ppath, &path_new);
  297.     if ( code < 0 ) return 0;
  298.     *ppath = path_new;
  299.     ppath->shares_segments = 0;
  300.     return ppath->current_subpath;
  301. }
  302.  
  303. /* ------ Debugging printout ------ */
  304.  
  305. #ifdef DEBUG
  306.  
  307. /* Print out a path with a label */
  308. void
  309. gx_dump_path(gx_path *ppath, char *tag)
  310. {    dprintf2("[p]Path %lx %s:\n", (ulong)ppath, tag);
  311.     gx_path_print(ppath);
  312. }
  313.  
  314. /* Print a path */
  315. void
  316. gx_path_print(gx_path *ppath)
  317. {    segment *pseg = (segment *)ppath->first_subpath;
  318.     dprintf5("   subpaths=%d, segments=%d, curves=%d, point=(%f,%f)\n",
  319.          ppath->subpath_count, ppath->segment_count,
  320.          ppath->curve_count, fixed2float(ppath->position.x),
  321.          fixed2float(ppath->position.y));
  322.     dprintf5("   box=(%f,%f),(%f,%f) last=%lx\n",
  323.          fixed2float(ppath->bbox.p.x), fixed2float(ppath->bbox.p.y),
  324.          fixed2float(ppath->bbox.q.x), fixed2float(ppath->bbox.q.y),
  325.          (ulong)ppath->box_last);
  326.     dprintf4("   cbox=(%f,%f),(%f,%f)\n",
  327.          fixed2float(ppath->cbox.p.x), fixed2float(ppath->cbox.p.y),
  328.          fixed2float(ppath->cbox.q.x), fixed2float(ppath->cbox.q.y));
  329.     while ( pseg )
  330.        {    gx_print_segment(pseg);
  331.         pseg = pseg->next;
  332.        }
  333. }
  334. void
  335. gx_print_segment(segment *pseg)
  336. {    char out[80];
  337.     sprintf(out, "   %lx<%lx,%lx>: %%s (%6g,%6g) ",
  338.         (ulong)pseg, (ulong)pseg->prev, (ulong)pseg->next,
  339.         fixed2float(pseg->pt.x), fixed2float(pseg->pt.y));
  340.     switch ( pseg->type )
  341.        {
  342.     case s_start:
  343. #define psub ((subpath *)pseg)
  344.         dprintf1(out, "start");
  345.         dprintf3("#lines=%d #curves=%d last=%lx",
  346.              psub->line_count, psub->curve_count,
  347.              (ulong)psub->last);
  348. #undef psub
  349.         break;
  350.     case s_curve:
  351.         dprintf1(out, "curve");
  352. #define pcur ((curve_segment *)pseg)
  353.         dprintf4("\n\tp1=(%f,%f) p2=(%f,%f)",
  354.              fixed2float(pcur->p1.x), fixed2float(pcur->p1.y),
  355.              fixed2float(pcur->p2.x), fixed2float(pcur->p2.y));
  356. #undef pcur
  357.         break;
  358.     case s_line:
  359.         dprintf1(out, "line");
  360.         break;
  361.     case s_line_close:
  362. #define plc ((line_close_segment *)pseg)
  363.         dprintf1(out, "close");
  364.         dprintf1(" %lx", (ulong)(plc->sub));
  365. #undef plc
  366.         break;
  367.     default:
  368.        {    char t[20];
  369.         sprintf(t, "type 0x%x", pseg->type);
  370.         dprintf1(out, t);
  371.        }
  372.        }
  373.     dputc('\n');
  374. }
  375.  
  376. #endif                    /* DEBUG */
  377.